package org.duang.upload;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.duang.config.Config;
import org.duang.kit.ToolsKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UploadFileRequest extends HttpServletRequestWrapper {

	private final static Logger logger = LoggerFactory.getLogger(UploadFileRequest.class);
	private List<UploadFile> uploadFiles;
	private com.oreilly.servlet.MultipartRequest multipartRequest;
	private String saveDir;
	private static final com.oreilly.servlet.multipart.FileRenamePolicy policy  = new RandomFileRenamePolicy();
	
	public UploadFileRequest(HttpServletRequest request, String saveDirectory){
		super(request);
		saveDir = (ToolsKit.isEmpty(saveDirectory)) ? Config.getUploadFileServerRootDirectory()+"/"+Config.getProductCode()
													: Config.getUploadFileServerRootDirectory() + "/" + Config.getProductCode()+ "/" +
													(saveDirectory.startsWith("/") ? saveDirectory.substring(1,saveDirectory.length()) : saveDirectory);
		wrapMultipartRequest(request, 
							 saveDir + "/" + ToolsKit.getCurrentDate("yyyyMMdd"),
							 Config.getMaxPostSize(),
							 Config.getEncoding());
	}

	
	/**
	 * 添加对相对路径的支持
	 */
	private String handleSaveDirectory(String saveDirectory) {
		return ToolsKit.getWebRootPath() + saveDirectory ;
	}
	
	@SuppressWarnings("unchecked")
	private void wrapMultipartRequest(HttpServletRequest request, String serverDir, int maxPostSize, String encoding){
		if(!OreillyCos.isOreillyCos){
			throw new RuntimeException("Oreilly cos.jar is not found, Multipart post can not be supported.");
		}
		String serverDir2 =  handleSaveDirectory(serverDir);
		logger.debug("serverDir: " +serverDir2);
		File directory = new File(serverDir2);
		if ( !directory.exists()) {
			if (!directory.mkdirs()) {
				throw new RuntimeException("Directory " + serverDir2 + " not exists and can not create directory.");
			}
		}
		
		uploadFiles = new ArrayList<UploadFile>();
		try {
			multipartRequest = new com.oreilly.servlet.MultipartRequest(request, serverDir2, maxPostSize, encoding, policy);
			Enumeration<String> files = multipartRequest.getFileNames();
			Enumeration<String> names = multipartRequest.getFileNames();
			while(files.hasMoreElements()){
				String name = files.nextElement();				
				String filesystemName = multipartRequest.getFilesystemName(name);
				String oiriginalName = names.nextElement();
				if(ToolsKit.isNotEmpty(filesystemName)){
					String originalFileName = multipartRequest.getOriginalFileName(name);
					String contentType = multipartRequest.getContentType(name);
					long fileSize = multipartRequest.getFile(name).length();					
					UploadFile uploadFile = new UploadFile(name, serverDir, filesystemName, oiriginalName, originalFileName, contentType, fileSize);
					if(isSafeFile(uploadFile)){
						uploadFiles.add(uploadFile);
					}
				}
			}
		} catch (IOException e) {
			logger.error("UploadFileRequest.wrapMultipartRequest() fail: "+ e.getMessage(),e);
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 取得上传成功的文件集合
	 * @return
	 */
	public List<UploadFile> getUploadFiles(){
		return uploadFiles;
	}
	
	private boolean isSafeFile(UploadFile uploadFile){
		if(!Config.getUploadFileExtNames().contains(uploadFile.getExtName().toLowerCase())){
			logger.warn("UploadFileRequest.isSafeFile() fail: "+ Config.getUploadFileExtNames()+ " is can't upload to server!");
			uploadFile.getFile().delete();
			return false;
		}
		return true;
	}

	/**
	 * 重写getParameterNames方法??
	 */
	public Enumeration getParameterNames() {
		return multipartRequest.getParameterNames();
	}
	
	public String getParameter(String name) {
		return multipartRequest.getParameter(name);
	}
	
	public String[] getParameterValues(String name) {
		return multipartRequest.getParameterValues(name);
	}
	
	
	@SuppressWarnings("unchecked")
	public Map getParameterMap() {
		Map map = new HashMap();
		Enumeration enumm = getParameterNames();
		while (enumm.hasMoreElements()) {
			String name = (String) enumm.nextElement();
			map.put(name, multipartRequest.getParameterValues(name));
		}
		return map;
	}
	

}

class RandomFileRenamePolicy implements com.oreilly.servlet.multipart.FileRenamePolicy{
	
	
	public RandomFileRenamePolicy(){
		
	}
	
    public File rename(File file){
    	try {
    		String fileName = verifiedFileExtName(file.getName());	//form表单input里的名称(上传前的名称)
    		String newName = createServerFileName(fileName);
        	File result = new File(file.getParentFile() , newName);
        	return result;	
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
    	
    }
    //uuid
    private String getServerFileName(){
        return java.util.UUID.randomUUID().toString().toLowerCase().replace("-", "");
    }
    //创建服务器端文件名
    private String createServerFileName(String fullName){
    	String name = getServerFileName();
    	String ext = "";//扩展名
    	char point = '.';
    	int index = fullName.lastIndexOf(point);      
    	if(index != -1){//如果有后缀
           ext = fullName.substring(index + 1);
    	}else{
           return fullName;
    	}
    	return name + point + ext;
    }
    /**
     * 验证上传文件扩展名是否合法
     * @param		上传文件名
     * @return		
     */
    private String verifiedFileExtName(String filesystemName){
    	boolean isUploadFileExtName = false;
    	Set<String> uploadFileExtName = Config.getUploadFileExtNames();		//允许上传的文件名
		for(String extName : uploadFileExtName){
			if(filesystemName.toLowerCase().endsWith(extName.toLowerCase())){
				isUploadFileExtName = true;
				break;
			}
		}
		//该文件的扩展名不允许上传到服务器
		if(!isUploadFileExtName){
			throw new IllegalArgumentException("UploadFileRequest.wrapMultipartRequest() fail: "+filesystemName+" not allow upload to server");
		}
		return filesystemName;
    }
}
